package com.strato.osgi.repository.v1_0_0.manifest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@SuppressWarnings("rawtypes")
public class ManifestParser {

	//copy from felix ManifestParser
		private static final int CLAUSE_START = 0;
		private static final int PARAMETER_START = 1;
		private static final int KEY = 2;
		private static final int DIRECTIVE_OR_TYPEDATTRIBUTE = 4;
		private static final int ARGUMENT = 8;
		private static final int VALUE = 16;
		private static final char EOF = (char) -1;
		
		 @SuppressWarnings("unchecked")
		public static List<ParsedHeaderClause> parseStandardHeader(String header)
		    {
		        List<ParsedHeaderClause> clauses = new ArrayList<ParsedHeaderClause>();
		        if (header == null)
		        {
		            return clauses;
		        }
		        ParsedHeaderClause clause = null;
		        String key = null;
		        Map targetMap = null;
		        int state = CLAUSE_START;
		        int currentPosition = 0;
		        int startPosition = 0;
		        int length = header.length();
		        boolean quoted = false;
		        boolean escaped = false;

		        char currentChar = EOF;
		        do
		        {
		            currentChar = charAt(currentPosition, header, length);
		            switch (state)
		            {
		                case CLAUSE_START:
		                    clause = new ParsedHeaderClause(
		                            new ArrayList<String>(),
		                            new HashMap<String, String>(),
		                            new HashMap<String, Object>(),
		                            new HashMap<String, String>());
		                    clauses.add(clause);
		                    state = PARAMETER_START;
		                case PARAMETER_START:
		                    startPosition = currentPosition;
		                    state = KEY;
		                case KEY:
		                    switch (currentChar)
		                    {
		                        case ':':
		                        case '=':
		                            key = header.substring(startPosition, currentPosition).trim();
		                            startPosition = currentPosition + 1;
		                            targetMap = clause.m_attrs;
		                            state = currentChar == ':' ? DIRECTIVE_OR_TYPEDATTRIBUTE : ARGUMENT;
		                            break;
		                        case EOF:
		                        case ',':
		                        case ';':
		                            clause.m_paths.add(header.substring(startPosition, currentPosition).trim());
		                            state = currentChar == ',' ? CLAUSE_START : PARAMETER_START;
		                            break;
		                        default:
		                            break;
		                    }
		                    currentPosition++;
		                    break;
		                case DIRECTIVE_OR_TYPEDATTRIBUTE:
		                    switch(currentChar)
		                    {
		                        case '=':
		                            if (startPosition != currentPosition)
		                            {
		                                clause.m_types.put(key, header.substring(startPosition, currentPosition).trim());
		                            }
		                            else
		                            {
		                                targetMap = clause.m_dirs;
		                            }
		                            state = ARGUMENT;
		                            startPosition = currentPosition + 1;
		                            break;
		                        default:
		                            break;
		                    }
		                    currentPosition++;
		                    break;
		                case ARGUMENT:
		                    if (currentChar == '\"')
		                    {
		                        quoted = true;
		                        currentPosition++;
		                    }
		                    else
		                    {
		                        quoted = false;
		                    }
		                    if (!Character.isWhitespace(currentChar)) {
		                    	state = VALUE;
		                    }
		                    else {
		                    	currentPosition++;
		                    }
		                    break;
		                case VALUE:
		                    if (escaped)
		                    {
		                        escaped = false;
		                    }
		                    else
		                    {
		                        if (currentChar == '\\' )
		                        {
		                            escaped = true;
		                        }
		                        else if (quoted && currentChar == '\"')
		                        {
		                            quoted = false;
		                        }
		                        else if (!quoted)
		                        {
		                            String value = null;
		                            switch(currentChar)
		                            {
		                                case EOF:
		                                case ';':
		                                case ',':
		                                    value = header.substring(startPosition, currentPosition).trim();
		                                    if (value.startsWith("\"") && value.endsWith("\""))
		                                    {
		                                        value = value.substring(1, value.length() - 1);
		                                    }
		                                    if (targetMap.put(key, value) != null)
		                                    {
		                                        throw new IllegalArgumentException(
		                                                "Duplicate '" + key + "' in: " + header);
		                                    }
		                                    state = currentChar == ';' ? PARAMETER_START : CLAUSE_START;
		                                    break;
		                                default:
		                                    break;
		                            }
		                        }
		                    }
		                    currentPosition++;
		                    break;
		                default:
		                    break;
		            }
		        } while ( currentChar != EOF);

		        if (state > PARAMETER_START)
		        {
		            throw new IllegalArgumentException("Unable to parse header: " + header);
		        }
		        return clauses;
		    }
	    
	    private static char charAt(int pos, String headers, int length)
	    {
	        if (pos >= length)
	        {
	            return EOF;
	        }
	        return headers.charAt(pos);
	    }

	    
	public static class ParsedHeaderClause
	{
	    public final List<String> m_paths;
	    public final Map<String, String> m_dirs;
	    public final Map<String, Object> m_attrs;
	    final Map<String, String> m_types;

	    public ParsedHeaderClause(
	        List<String> paths, Map<String, String> dirs, Map<String, Object> attrs,
	        Map<String, String> types)
	    {
	        m_paths = paths;
	        m_dirs = dirs;
	        m_attrs = attrs;
	        m_types = types;
	    }
	}
	
}
